import os.path
# -*- coding: utf-8 -*-
__revision__ = "$Id: tests.py 372 2008-12-03 10:51:36Z dinoboff $"

from mock			import Mock, patch
from utils.common	import create_file
from zipfile		import ZipFile
import codecs
import logging
import os
import re
import shutil
import sys
import tempfile
import unittest
import utils

FILE_CHARSET = utils.settings.FILE_CHARSET

openurl_i = Mock()
openurl_i.read.return_value = u"0.1.0|http://lussumo.com/addons/index.php?PostBackAction=AddOn&AddOnID=1"
openurl_c = Mock()
openurl_c.return_value = openurl_i
stdout_i = Mock()
stderr_i = Mock()

class TestVanillaFriendsUtils(unittest.TestCase):
	def setUp(self):
		self.temp_folder = unicode(tempfile.mkdtemp(), sys.getdefaultencoding())

	def tearDown(self):
		shutil.rmtree(self.temp_folder)

	def testFixEOL(self):
		file_path = create_file(
			'foo', content=u'foo\r\nfoo\xff', base_dir=self.temp_folder)
		self.assertEquals(u'foo\r\nfoo\xff',
						  codecs.open(file_path, 'rb', FILE_CHARSET).read())
		utils.common.fix_eol(file_path)
		self.assertEquals(u'foo\nfoo\xff',
						  codecs.open(file_path, 'rb', FILE_CHARSET).read())
		utils.common.fix_eol(file_path,eol='\r\n')
		self.assertEquals(u'foo\r\nfoo\xff',
						  codecs.open(file_path, 'rb', FILE_CHARSET).read())
		self.assertRaises(utils.UtilsError, utils.common.fix_eol, self.temp_folder + u'/bar')

	def testReplaceTokens(self):
		file_path = create_file(
			u'foo', content=u'foo@@BAR@@baz\xff', base_dir=self.temp_folder)
		utils.common.replace_tokens(file_path,{u'FOO': u'', u'BAR': u'bar'})
		self.assertEquals(u'foobarbaz\xff',
						  codecs.open(file_path, 'rb', FILE_CHARSET).read())

		file_path = create_file(
			u'bar', content=u'foo%%BAR%%baz', base_dir=self.temp_folder)
		utils.common.replace_tokens(file_path,{u'FOO': u'', u'BAR': u'bar'}, delimiter='%%')
		self.assertEquals(u'foobarbaz',
						  codecs.open(file_path, 'rb', FILE_CHARSET).read())
		
		self.assertRaises(utils.UtilsError, utils.common.replace_tokens,
						  self.temp_folder + u'/baz', {u'foo':u'bar'})

	def testLoggerFilterFactory(self):
		r1 = logging.LogRecord('foo', '1', u'bar', 1, u'baz', (), sys.exc_info())
		r20 = logging.LogRecord('foo', '20', u'bar', 1, u'baz', (), sys.exc_info())
		r25 = logging.LogRecord('foo', '25', u'bar', 1, u'baz', (), sys.exc_info())
		r40 = logging.LogRecord('foo', '40', u'bar', 1, u'baz', (), sys.exc_info())
		r60 = logging.LogRecord('foo', '60', u'bar', 1, u'baz', (), sys.exc_info())
		
		f0 = utils.common.logger_filter_factory(0,25,'foo')
		f1 = utils.common.logger_filter_factory(25,60,'foo')
		
		self.assertTrue(f0.filter(r1))
		self.assertTrue(f0.filter(r20))
		self.assertTrue(f0.filter(r25))
		self.assertFalse(f0.filter(r40))
		self.assertFalse(f0.filter(r60))
		
		self.assertFalse(f1.filter(r1))
		self.assertFalse(f1.filter(r20))
		self.assertFalse(f1.filter(r25))
		self.assertTrue(f1.filter(r40))
		self.assertTrue(f1.filter(r60))

	@patch('sys.stdout', stdout_i)
	@patch('sys.stderr', stderr_i)
	def testLoggerFactoryDefaultLevel(self):
		log = utils.common.logger_factory(
			name='test',
			filter_name='test',
			formatter=logging.Formatter("MESSAGE: %(message)s"))
		log.info(u'foo')
		log.critical(u'bar')
		self.assertFalse(stdout_i.write.called)
		self.assertEqual(stderr_i.write.call_args[0][0].strip(), u'MESSAGE: bar')
		stdout_i.reset()
		stderr_i.reset()

	@patch('sys.stdout', stdout_i)
	@patch('sys.stderr', stderr_i)
	def testLoggerFactoryInfoLevel(self):
		log = utils.common.logger_factory(
			name='test',
			level=logging.INFO,
			filter_name='test')
		log.info(u'foo')
		self.assertFalse(stderr_i.write.called)
		self.assertEqual(stdout_i.write.call_args[0][0].strip(), u'INFO: foo')
		stdout_i.reset()
		stderr_i.reset()
		log.critical(u'bar')
		self.assertFalse(stdout_i.write.called)
		self.assertEqual(stderr_i.write.call_args[0][0].strip(), u'CRITICAL: bar')
		stdout_i.reset()
		stderr_i.reset()

	def testCreateFile(self):
		content = u'اختبار'
		create_file(u'foo', content, self.temp_folder)
		self.assertTrue(os.path.exists(self.temp_folder + '/foo'))
		self.assertEqual(
			unicode(open(self.temp_folder + '/foo', 'rb').read(), FILE_CHARSET),
			content)

class TestBuilder(unittest.TestCase):
	
	INCLUDE_FILE = (
		u'include.txt',
		u'include/include.txt',
		u'default.php',
	)
	EXCLUDE_FILE = (
		u'exclude.bar',
		u'.svn/exclude.txt',
		u'.svn/exclude.txt',
		u'test/exclude.txt',
		u'.svn/text-base/readme.html.svn-base',
	)
	EXTENSION_HEADER =u"""<?php
	/**
	Extension Name: %(title)s
	Extension Url: %(url)s
	Description: %(desc)s
	Version: %(version)s
	Author: %(author)s
	Author Url: %(auth_url)s
	 */
	"""
	EXTENSION_DETAILS = {
		u'title':		u'Low-Cal Vanilla',
		u'dist_name':	u'LowCalVanilla',
		u'url': 		u'http://lussumo.com/addons/index.php?PostBackAction=AddOn&AddOnID=315',
		u'desc': 		u'Optimize page load',
		u'version': 	u'0.1.1',
		u'author': 		u'Damien Lebrun',
		u'auth_url': 	u'http://lussumo.com/community/account/2469/'
	}
	
	JS_FILE = u"""
	/**
	 * foo
	 */
	 var foo;
	 foo = 'bar';
	"""

	def setUp(self):
		self.temp_folder = unicode(tempfile.mkdtemp(), sys.getdefaultencoding())

	def tearDown(self):
		shutil.rmtree(self.temp_folder)
	
	def testFindFilesToPackWithTargetDirectory(self):
		self._set_assets(u'foo')
		s = utils.Builder(
			base_dir=os.path.join(self.temp_folder, u'foo'))
		files = s.find_files_to_pack()
		for test_file in self.INCLUDE_FILE:
			experted_file = os.path.join(self.temp_folder, u'foo', test_file)
			self.assertTrue(
				os.path.normpath(experted_file) in files)
		for test_file in self.EXCLUDE_FILE:
			experted_file = os.path.join(self.temp_folder, u'foo', test_file)
			self.assertFalse(
				os.path.normpath(experted_file) in files)

	def testFindFilesToPack(self):
		self._set_assets()
		s = utils.Builder(base_dir=self.temp_folder)
		files = s.find_files_to_pack()
		for test_file in self.INCLUDE_FILE:
			experted_file = os.path.join(self.temp_folder, test_file)
			self.assertTrue(
				os.path.normpath(experted_file) in files)
		for test_file in self.EXCLUDE_FILE:
			experted_file = os.path.join(self.temp_folder, test_file)
			self.assertFalse(
				os.path.normpath(experted_file) in files)

	def testNormPatterns(self):
		s = utils.Builder()
		pat, pre = s._norm_patterns(u'*/*', None)
		self.assertEqual(pat, u'*%s*' % os.path.sep)
		self.assertEqual(pre, None)
		pat, pre = s._norm_patterns(u'*', u'foo/bar')
		self.assertEqual(pat, u'*')
		self.assertEqual(pre, os.path.abspath(u'foo/bar'))
		pat, pre = s._norm_patterns(u'*', u'.')
		self.assertEqual(pat, u'*')
		self.assertEqual(pre, None)

	def testNormPatternsWithTargetDirectory(self):
		s = utils.Builder(base_dir=u'baz')
		pat, pre = s._norm_patterns(u'*/*', None)
		self.assertEqual(pat, u'*%s*' % os.path.sep)
		self.assertEqual(pre, None)
		pat, pre = s._norm_patterns(u'*', u'foo/bar')
		self.assertEqual(pat, u'*')
		self.assertEqual(pre, os.path.abspath(u'baz/foo/bar'))
		pat, pre = s._norm_patterns(u'*', u'.')
		self.assertEqual(pat, u'*')
		self.assertEqual(pre, None)

	def testCopyFile(self):
		file_path = create_file(u'foo/bar/baz.txt', base_dir=self.temp_folder)
		base_dst = os.path.join(self.temp_folder, u'build')
		os.mkdir(os.path.join(self.temp_folder, u'build'))
		s = utils.Builder(base_dir=self.temp_folder)
		s._copy_file(file_path, base_dst)
		self.assertTrue(os.path.exists(os.path.join(
			base_dst,
			u'foo/bar/baz.txt')))

	def testClean(self):
		build_dir = os.path.join(self.temp_folder, u'build')
		dist_dir = os.path.join(self.temp_folder, u'dist')
		os.makedirs(build_dir)
		os.makedirs(dist_dir)
		s = utils.Builder(base_dir=self.temp_folder)
		s.clean()
		self.assertFalse(os.path.exists(build_dir))
		self.assertFalse(os.path.exists(dist_dir))

	@patch('urllib.urlopen', openurl_c)
	def testGetDetailsFromLussumo(self):
		s = utils.Builder(base_dir=self.temp_folder)
		version, url = s.get_details_from_lussumo(u'Low-cal Vanilla')
		self.assertEqual(version, u'0.1.0')
		self.assertEqual(url, u'http://lussumo.com/addons/index.php?PostBackAction=AddOn&AddOnID=1')
		args, kargs = openurl_c.call_args
		self.assertEqual(args[0], u'http://lussumo.com/updatecheck/default.php?Extension=Low-cal+Vanilla')

	@patch('urllib.urlopen', openurl_c)
	def testGetExtensionDetails(self):
		s = utils.Builder(base_dir=self.temp_folder)
		self._set_default_file()
		Details = s.get_extension_details()
		self.assertEqual(Details[u'EXT_NAME'], 		self.EXTENSION_DETAILS[u'title'])
		self.assertEqual(Details[u'EXT_URL'],		self.EXTENSION_DETAILS[u'url'])
		self.assertEqual(Details[u'DESCRIPTION'], 	self.EXTENSION_DETAILS[u'desc'])
		self.assertEqual(Details[u'VERSION'], 		self.EXTENSION_DETAILS[u'version'])
		self.assertEqual(Details[u'AUTHOR'], 		self.EXTENSION_DETAILS[u'author'])
		self.assertEqual(Details[u'AUTHOR_URL'], 	self.EXTENSION_DETAILS[u'auth_url'])
		self.assertEqual(Details[u'DIST_NAME'], 	self.EXTENSION_DETAILS[u'dist_name'])
		self.assertEqual(s.old_version, u'0.1.0')

	@patch('urllib.urlopen', openurl_c)
	def testGetExtensionDetailsSpecifiedDistName(self):
		s = utils.Builder(base_dir=self.temp_folder, dist_name='Foo')
		self._set_default_file()
		Details = s.get_extension_details()
		self.assertEqual(Details[u'EXT_NAME'], 		self.EXTENSION_DETAILS[u'title'])
		self.assertEqual(Details[u'EXT_URL'], 		self.EXTENSION_DETAILS[u'url'])
		self.assertEqual(Details[u'DESCRIPTION'], 	self.EXTENSION_DETAILS[u'desc'])
		self.assertEqual(Details[u'VERSION'], 		self.EXTENSION_DETAILS[u'version'])
		self.assertEqual(Details[u'AUTHOR'], 		self.EXTENSION_DETAILS[u'author'])
		self.assertEqual(Details[u'AUTHOR_URL'], 	self.EXTENSION_DETAILS[u'auth_url'])
		self.assertEqual(Details[u'DIST_NAME'], 	u'Foo')
		self.assertEqual(s.old_version, u'0.1.0')

	def testNormName(self):
		s = utils.Builder(base_dir=self.temp_folder)
		self.assertEqual(
			s._normalize_name(u'Low-Cal Vanilla'),
			u'LowCalVanilla')
		self.assertEqual(
			s._normalize_name(u"Low-Cal Vanilla / That Guy's fork"),
			u'LowCalVanillaThatGuysFork')
		self.assertEqual(
			s._normalize_name(u"1.0.2a3"),u'1.0.2a3')

	def testPrepare(self):
		build_dir = os.path.join(self.temp_folder, u'build')
		build_ext_dir = os.path.join(build_dir, u'Foo')
		dist_dir = os.path.join(self.temp_folder, u'dist')
		self._set_default_file()
		s = utils.Builder(base_dir=self.temp_folder, dist_name=u'Foo')
		self.assertEqual(s.prepare(), build_ext_dir)
		self.assertTrue(os.path.exists(build_dir))
		self.assertTrue(os.path.exists(build_ext_dir))
		self.assertTrue(os.path.exists(dist_dir))

	@patch('urllib.urlopen', openurl_c)
	def testBuild(self):
		s = utils.Builder(base_dir=self.temp_folder)
		# Create a Low-Cal Vanilla define by files in INCLUDE_FILE and EXCLUDE_FILE
		# and the extension details defined in EXTENSION_DETAILS
		self._set_assets()
		self._set_default_file()
		s.build()

		# check files in build/
		for test_file in self.INCLUDE_FILE:
			expected_file = os.path.join(self.temp_folder, u'build', u'LowCalVanilla', test_file)
			self.assertTrue(os.path.exists(expected_file))
		for test_file in self.EXCLUDE_FILE:
			expected_file = os.path.join(self.temp_folder, u'build', u'LowCalVanilla', test_file)
			self.assertFalse(os.path.exists(expected_file))

		# check zip file
		self.assertTrue(os.path.exists(self.temp_folder+u'/dist/LowCalVanilla-0.1.1.zip'))
		archive = ZipFile(self.temp_folder+u'/dist/LowCalVanilla-0.1.1.zip')
		archive_members = archive.namelist()
		archive.close()
		for test_file in self.INCLUDE_FILE:
			self.assertTrue(u'LowCalVanilla/'+test_file in archive_members)
		for test_file in self.EXCLUDE_FILE:
			self.assertFalse(u'LowCalVanilla/'+test_file in archive_members)

	def testMinfyAssets(self):
		yui = os.path.join(
				os.path.dirname(os.path.abspath(os.curdir)),
				"JAR/yuicompressor.jar")
		create_file(u'test.js', self.JS_FILE, self.temp_folder)
		dst = os.path.join(self.temp_folder, 'Foo')
		os.makedirs(dst)
		s = utils.Builder(base_dir=self.temp_folder)
		s.minfy_assets(dst,	yuicompressor_path=yui)
		self.assertTrue(os.path.exists(dst+'/test.js'))
		self.assertEqual('var foo;foo="bar";', open(dst+'/test.js', 'r').read())

	def testBuildDoc(self):
		self._set_default_file()
		s = utils.Builder(base_dir=self.temp_folder, dist_name='Foo')
		s.prepare()
		
		create_file(u'build/Foo/test.rst', u'*foo*', self.temp_folder)
		self.assertTrue(os.path.exists(self.temp_folder+'/build/Foo/test.rst'))
		s.build_doc()
		self.assertFalse(os.path.exists(self.temp_folder+'/build/Foo/test.rst'))
		self.assertTrue(os.path.exists(self.temp_folder+'/build/Foo/test.html'))
		
		html_doc = open(self.temp_folder+'/build/Foo/test.html', 'rb').read()
		self.assertTrue(
			re.compile('<h1[-_"=\w\d\s]*>\s*Low-Cal Vanilla\s*</h1>',
					   re.MULTILINE).search(html_doc))
		self.assertTrue(
			re.compile('<p>\s*<em>\s*foo\s*</em>\s*</p>',
					   re.MULTILINE).search(html_doc))

	def _set_default_file(self):
		create_file(u'default.php',
					self.EXTENSION_HEADER % self.EXTENSION_DETAILS,
					self.temp_folder)

	def _set_assets(self, base_dir=None):
		if base_dir:
			base_dir = os.path.join(self.temp_folder, base_dir)
		else:
			base_dir = self.temp_folder

		for file_path in self.INCLUDE_FILE:
			create_file(file_path, base_dir=base_dir)
		for file_path in self.EXCLUDE_FILE:
			create_file(file_path, base_dir=base_dir)
			


class TestCreator(unittest.TestCase):
	def setUp(self):
		self.temp_folder = unicode(tempfile.mkdtemp(), sys.getdefaultencoding())

	def tearDown(self):
		shutil.rmtree(self.temp_folder)

	def testCreate(self):
		c = utils.Creator('foo-bar', base_dir=self.temp_folder)
		self.assertEqual('foo-bar', c.name)
		self.assertEqual('FooBar', c.dist_name, 'Creator didn\'t normalize name correctly')

		c.create()
		for path in (
			'default.php', '.htaccess', 'readme.rst',
			'assets', 'assets/.htaccess',
			'library', 'library/functions.php',
			'theme'):
			self.assertTrue(os.path.exists(
				os.path.join(self.temp_folder, 'FooBar', path)), 'did\'nt find "%s".' % path)

	def testCreateUnicodeExtension(self):
		dist_name = u'اختبار'
		c = utils.Creator(dist_name, base_dir=self.temp_folder)
		self.assertEqual(dist_name, c.name)
		self.assertEqual(dist_name, c.dist_name)

		c.create()
		for path in (
			'default.php', '.htaccess', 'readme.rst',
			'assets', 'assets/.htaccess',
			'library', 'library/functions.php',
			'theme'):
			self.assertTrue(os.path.exists(
				os.path.join(self.temp_folder, dist_name, path)), 'did\'nt find "%s".' % path)

		default_content = unicode(open(
			os.path.join(self.temp_folder, dist_name, 'default.php'),
			'rb').read(), FILE_CHARSET)
		self.assertEqual(
			default_content,
			utils.settings.TEMPLATE_DEFAULT % {'EXT_NAME': dist_name})

if __name__ == '__main__':
	unittest.main()
